/*
 * CentralizedMeView.java
 */

package centralizedme;

import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.HashMap;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JTextField;

/**
 * The application's main frame.
 */
public class CentralizedMeView extends FrameView {
    // rdf model to work with rdf data
    private RdfModel model;
    // foaf logic object
    private FoafLogic foaf;
    // ArrayList of form components from the ui
    private HashMap<String, JTextField> components;

    /**
     * Constructor for CentralizedMeView.
     * @param app   <code>SingleFrameApplication</code> object.
     */
    public CentralizedMeView(SingleFrameApplication app) {
        super(app);

        // member objects to hold logic
        model = new RdfModel();
        foaf = new FoafLogic();

        // initialize components
        initComponents();

        // store necessary components in an ArrayList
        components = new HashMap<String, JTextField>();
        components.put("foaf:givenname", firstName);
        components.put("foaf:family_name", lastName);
        components.put("foaf:title", title);
        components.put("foaf:nick", nick);
        components.put("foaf:homepage", homepage);
        components.put("foaf:openid", openId);
        components.put("foaf:mbox", email);

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String)(evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer)(evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }

    /**
     * Show the about box for the application.
     */
    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = CentralizedMeApp.getApplication().getMainFrame();
            aboutBox = new CentralizedMeAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        CentralizedMeApp.getApplication().show(aboutBox);
    }

    /**
     * Show the rdfView box containing a textarea with FOAF rdf.
     */
    @Action
    public void showRdfView() {
        if (dataError()) {
            CentralizedMeApp.getApplication().show(noDataError);
        } else {
            if (viewRdf == null) {
                JFrame mainFrame = CentralizedMeApp.getApplication().getMainFrame();
                viewRdf.setLocationRelativeTo(mainFrame);
            }
            buildModel();
            viewRdfText.setText(model.toString());
            CentralizedMeApp.getApplication().show(viewRdf);
        }
    }

    /**
     * Action listener method for capturing user clicks.
     * @param e <code>ActionEvent</code> object.
     * @throws centralizedme.NoPropertyFound    If no valid property is found
     * when reading in a FOAF file.
     */
    @Action
    public void actionPerformed(ActionEvent e) throws NoPropertyFound {
        if (e.getSource() == openMenuItem) {
            int returnVal = openDialog.showOpenDialog(null);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = openDialog.getSelectedFile();
                HashMap<String, String> properties = foaf.foafFileRead(file);
                setTextFields(properties);
            } else {
                System.err.println("File open cancelled by user");
            }
        } else if (e.getSource() == saveMenuItem || e.getSource() == saveButton) {
            if (dataError()) {
                CentralizedMeApp.getApplication().show(noDataError);
            } else {
                int returnVal = saveDialog.showSaveDialog(null);
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    File file = saveDialog.getSelectedFile();
                    foaf.saveFoafFile(components, file);
                } else {
                    System.err.println("File save cancelled by user");
                }
            }
        } else if (e.getSource() == noDataOK) {
            noDataError.setVisible(false);
        } else {
            System.err.println("Action not implemented");
        }
    }

    /**
     * Lookup information from a parsed FOAF file and place into text fields.
     * @param properties    <code>HashMap</code> containing found properties
     * from the loaded file.
     */
    private void setTextFields(HashMap<String, String> properties) {
        // use the components HashMap and the properties Hashtable to look
        // for valid user entries
        Object[] keys = components.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            if (properties.containsKey((String) keys[i])) {
                components.get((String) keys[i]).setText(
                        (String) properties.get((String) keys[i]));
            }
        }
    }

    /**
     * Helper function that updates the FOAF RDF model.
     */
    private void buildModel() {
        model = foaf.buildModel(components);
    }

    /**
     * Check that a minimum amount of information has been entered.
     * @return
     */
    private boolean dataError() {
        if (firstName.getText().equals("")
                    || lastName.getText().equals("")
                    || email.getText().equals("")) {
            return true;
        } else {
            return false;
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        categoryTabs = new javax.swing.JTabbedPane();
        basicsTab = new javax.swing.JPanel();
        firstName = new javax.swing.JTextField();
        firstNameLabel = new javax.swing.JLabel();
        lastNameLabel = new javax.swing.JLabel();
        lastName = new javax.swing.JTextField();
        title = new javax.swing.JTextField();
        titleLabel = new javax.swing.JLabel();
        titleHelp = new javax.swing.JLabel();
        nick = new javax.swing.JTextField();
        nickLabel = new javax.swing.JLabel();
        onlineTab = new javax.swing.JPanel();
        homepage = new javax.swing.JTextField();
        homepageLabel = new javax.swing.JLabel();
        openId = new javax.swing.JTextField();
        openIdLabel = new javax.swing.JLabel();
        emailLabel = new javax.swing.JLabel();
        email = new javax.swing.JTextField();
        saveButton = new javax.swing.JButton();
        viewRdfButton = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        openMenuItem = new javax.swing.JMenuItem();
        saveMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        viewRdf = new javax.swing.JDialog();
        viewRdfTextLabel = new javax.swing.JLabel();
        viewRdfPane = new javax.swing.JScrollPane();
        viewRdfText = new javax.swing.JTextArea();
        openDialog = new javax.swing.JFileChooser();
        saveDialog = new javax.swing.JFileChooser();
        noDataError = new javax.swing.JDialog();
        noDataErrorMessage = new javax.swing.JLabel();
        noDataOK = new javax.swing.JButton();

        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setPreferredSize(new java.awt.Dimension(500, 350));
        mainPanel.setRequestFocusEnabled(false);

        categoryTabs.setMaximumSize(new java.awt.Dimension(500, 350));
        categoryTabs.setName("categoryTabs"); // NOI18N
        categoryTabs.setPreferredSize(new java.awt.Dimension(500, 350));

        basicsTab.setName("basicsTab"); // NOI18N
        basicsTab.setPreferredSize(new java.awt.Dimension(500, 350));

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(centralizedme.CentralizedMeApp.class).getContext().getResourceMap(CentralizedMeView.class);
        firstName.setText(resourceMap.getString("firstName.text")); // NOI18N
        firstName.setName("firstName"); // NOI18N

        firstNameLabel.setText(resourceMap.getString("firstNameLabel.text")); // NOI18N
        firstNameLabel.setName("firstNameLabel"); // NOI18N

        lastNameLabel.setText(resourceMap.getString("lastNameLabel.text")); // NOI18N
        lastNameLabel.setName("lastNameLabel"); // NOI18N

        lastName.setName("lastName"); // NOI18N

        title.setName("title"); // NOI18N

        titleLabel.setText(resourceMap.getString("titleLabel.text")); // NOI18N
        titleLabel.setName("titleLabel"); // NOI18N

        titleHelp.setFont(resourceMap.getFont("titleHelp.font")); // NOI18N
        titleHelp.setText(resourceMap.getString("titleHelp.text")); // NOI18N
        titleHelp.setName("titleHelp"); // NOI18N

        nick.setName("nick"); // NOI18N

        nickLabel.setText(resourceMap.getString("nickLabel.text")); // NOI18N
        nickLabel.setName("nickLabel"); // NOI18N

        javax.swing.GroupLayout basicsTabLayout = new javax.swing.GroupLayout(basicsTab);
        basicsTab.setLayout(basicsTabLayout);
        basicsTabLayout.setHorizontalGroup(
            basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(basicsTabLayout.createSequentialGroup()
                .addGap(66, 66, 66)
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(firstNameLabel)
                    .addComponent(lastNameLabel)
                    .addComponent(nickLabel)
                    .addComponent(titleLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(firstName, javax.swing.GroupLayout.Alignment.CENTER, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lastName, javax.swing.GroupLayout.Alignment.CENTER, javax.swing.GroupLayout.PREFERRED_SIZE, 253, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(nick, javax.swing.GroupLayout.Alignment.CENTER, javax.swing.GroupLayout.DEFAULT_SIZE, 253, Short.MAX_VALUE)
                    .addComponent(title, javax.swing.GroupLayout.Alignment.CENTER, javax.swing.GroupLayout.DEFAULT_SIZE, 253, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(titleHelp)
                .addGap(289, 289, 289))
        );

        basicsTabLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {firstName, lastName, nick, title});

        basicsTabLayout.setVerticalGroup(
            basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(basicsTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(firstName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(firstNameLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lastName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lastNameLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(title, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(titleHelp)
                    .addComponent(titleLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(basicsTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(nick, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(nickLabel))
                .addContainerGap(180, Short.MAX_VALUE))
        );

        categoryTabs.addTab(resourceMap.getString("basicsTab.TabConstraints.tabTitle"), basicsTab); // NOI18N

        onlineTab.setName("onlineTab"); // NOI18N
        onlineTab.setPreferredSize(new java.awt.Dimension(500, 350));

        homepage.setName("homepage"); // NOI18N

        homepageLabel.setText(resourceMap.getString("homepageLabel.text")); // NOI18N
        homepageLabel.setName("homepageLabel"); // NOI18N

        openId.setName("openId"); // NOI18N

        openIdLabel.setText(resourceMap.getString("openIdLabel.text")); // NOI18N
        openIdLabel.setName("openIdLabel"); // NOI18N

        emailLabel.setText(resourceMap.getString("emailLabel.text")); // NOI18N
        emailLabel.setName("emailLabel"); // NOI18N

        email.setName("email"); // NOI18N

        javax.swing.GroupLayout onlineTabLayout = new javax.swing.GroupLayout(onlineTab);
        onlineTab.setLayout(onlineTabLayout);
        onlineTabLayout.setHorizontalGroup(
            onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(onlineTabLayout.createSequentialGroup()
                .addGap(59, 59, 59)
                .addGroup(onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(emailLabel)
                    .addComponent(openIdLabel)
                    .addComponent(homepageLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(homepage, javax.swing.GroupLayout.PREFERRED_SIZE, 250, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(email, javax.swing.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE)
                    .addComponent(openId, javax.swing.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE))
                .addGap(294, 294, 294))
        );

        onlineTabLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {email, homepage, openId});

        onlineTabLayout.setVerticalGroup(
            onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(onlineTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(homepage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(homepageLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(openId, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(openIdLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(onlineTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(emailLabel)
                    .addComponent(email, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(206, Short.MAX_VALUE))
        );

        categoryTabs.addTab(resourceMap.getString("onlineTab.TabConstraints.tabTitle"), onlineTab); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(centralizedme.CentralizedMeApp.class).getContext().getActionMap(CentralizedMeView.class, this);
        saveButton.setAction(actionMap.get("actionPerformed")); // NOI18N
        saveButton.setText(resourceMap.getString("saveButton.text")); // NOI18N
        saveButton.setName("saveButton"); // NOI18N

        viewRdfButton.setAction(actionMap.get("showRdfView")); // NOI18N
        viewRdfButton.setText(resourceMap.getString("viewRdfButton.text")); // NOI18N
        viewRdfButton.setName("viewRdfButton"); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(categoryTabs, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(viewRdfButton)
                .addGap(18, 18, 18)
                .addComponent(saveButton)
                .addContainerGap(325, Short.MAX_VALUE))
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addComponent(categoryTabs, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(saveButton)
                    .addComponent(viewRdfButton))
                .addContainerGap())
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        openMenuItem.setAction(actionMap.get("actionPerformed")); // NOI18N
        openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        openMenuItem.setText(resourceMap.getString("openMenuItem.text")); // NOI18N
        openMenuItem.setName("openMenuItem"); // NOI18N
        fileMenu.add(openMenuItem);

        saveMenuItem.setAction(actionMap.get("actionPerformed")); // NOI18N
        saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveMenuItem.setText(resourceMap.getString("saveMenuItem.text")); // NOI18N
        saveMenuItem.setName("saveMenuItem"); // NOI18N
        fileMenu.add(saveMenuItem);

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N
        statusPanel.setPreferredSize(new java.awt.Dimension(350, 30));

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 317, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        viewRdf.setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
        viewRdf.setName("viewRdf"); // NOI18N

        viewRdfTextLabel.setText(resourceMap.getString("viewRdfTextLabel.text")); // NOI18N
        viewRdfTextLabel.setName("viewRdfTextLabel"); // NOI18N

        viewRdfPane.setName("viewRdfPane"); // NOI18N

        viewRdfText.setColumns(20);
        viewRdfText.setEditable(false);
        viewRdfText.setRows(5);
        viewRdfText.setName("viewRdfText"); // NOI18N
        viewRdfPane.setViewportView(viewRdfText);

        javax.swing.GroupLayout viewRdfLayout = new javax.swing.GroupLayout(viewRdf.getContentPane());
        viewRdf.getContentPane().setLayout(viewRdfLayout);
        viewRdfLayout.setHorizontalGroup(
            viewRdfLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(viewRdfLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(viewRdfLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(viewRdfPane, javax.swing.GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE)
                    .addComponent(viewRdfTextLabel))
                .addContainerGap())
        );
        viewRdfLayout.setVerticalGroup(
            viewRdfLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(viewRdfLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(viewRdfTextLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(viewRdfPane, javax.swing.GroupLayout.DEFAULT_SIZE, 236, Short.MAX_VALUE)
                .addContainerGap())
        );

        openDialog.setName("openDialog"); // NOI18N

        saveDialog.setDialogTitle(resourceMap.getString("saveDialog.dialogTitle")); // NOI18N
        saveDialog.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
        saveDialog.setName("saveDialog"); // NOI18N

        noDataError.setTitle(resourceMap.getString("noDataError.title")); // NOI18N
        noDataError.setModal(true);
        noDataError.setName("noDataError"); // NOI18N
        noDataError.setResizable(false);

        noDataErrorMessage.setBackground(resourceMap.getColor("noDataErrorMessage.background")); // NOI18N
        noDataErrorMessage.setFont(resourceMap.getFont("noDataErrorMessage.font")); // NOI18N
        noDataErrorMessage.setForeground(resourceMap.getColor("noDataErrorMessage.foreground")); // NOI18N
        noDataErrorMessage.setText(resourceMap.getString("noDataErrorMessage.text")); // NOI18N
        noDataErrorMessage.setName("noDataErrorMessage"); // NOI18N

        noDataOK.setAction(actionMap.get("actionPerformed")); // NOI18N
        noDataOK.setText(resourceMap.getString("noDataOK.text")); // NOI18N
        noDataOK.setName("noDataOK"); // NOI18N

        javax.swing.GroupLayout noDataErrorLayout = new javax.swing.GroupLayout(noDataError.getContentPane());
        noDataError.getContentPane().setLayout(noDataErrorLayout);
        noDataErrorLayout.setHorizontalGroup(
            noDataErrorLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(noDataErrorLayout.createSequentialGroup()
                .addGroup(noDataErrorLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(noDataErrorLayout.createSequentialGroup()
                        .addGap(155, 155, 155)
                        .addComponent(noDataOK))
                    .addGroup(noDataErrorLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(noDataErrorMessage)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        noDataErrorLayout.setVerticalGroup(
            noDataErrorLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(noDataErrorLayout.createSequentialGroup()
                .addGap(37, 37, 37)
                .addComponent(noDataErrorMessage)
                .addGap(29, 29, 29)
                .addComponent(noDataOK)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel basicsTab;
    private javax.swing.JTabbedPane categoryTabs;
    private javax.swing.JTextField email;
    private javax.swing.JLabel emailLabel;
    private javax.swing.JTextField firstName;
    private javax.swing.JLabel firstNameLabel;
    private javax.swing.JTextField homepage;
    private javax.swing.JLabel homepageLabel;
    private javax.swing.JTextField lastName;
    private javax.swing.JLabel lastNameLabel;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JTextField nick;
    private javax.swing.JLabel nickLabel;
    private javax.swing.JDialog noDataError;
    private javax.swing.JLabel noDataErrorMessage;
    private javax.swing.JButton noDataOK;
    private javax.swing.JPanel onlineTab;
    private javax.swing.JFileChooser openDialog;
    private javax.swing.JTextField openId;
    private javax.swing.JLabel openIdLabel;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JButton saveButton;
    private javax.swing.JFileChooser saveDialog;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JTextField title;
    private javax.swing.JLabel titleHelp;
    private javax.swing.JLabel titleLabel;
    private javax.swing.JDialog viewRdf;
    private javax.swing.JButton viewRdfButton;
    private javax.swing.JScrollPane viewRdfPane;
    private javax.swing.JTextArea viewRdfText;
    private javax.swing.JLabel viewRdfTextLabel;
    // End of variables declaration//GEN-END:variables

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;

}